package metamodel;

import antlr.TokenStreamException;
import antlr.RecognitionException;
import junit.framework.TestCase;

import java.io.StringWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.ArrayList;

import metamodel.misc.XMLSerializer;

/**
 * User: felix
 * Date: 17.06.2005
 */
public class PolyTest extends TestCase {
    public static class Person{
        public Person() {
        }

        public Person(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public ContactInfo getContactInfo() {
            return contactInfo;
        }

        public void setContactInfo(ContactInfo contactInfo) {
            this.contactInfo = contactInfo;
        }

        String name;
        ContactInfo contactInfo;
        List secondaryInfos;

        public List getSecondaryInfos() {
            if (secondaryInfos ==null){
                secondaryInfos =new ArrayList(4);
            }
            return secondaryInfos;
        }

        public void setSecondaryInfos(List secondaryInfos) {
            this.secondaryInfos = secondaryInfos;
        }

    }

    public abstract static class ContactInfo{

    }

    public static class PhoneInfo extends ContactInfo{

        String phoneNr;

        public PhoneInfo() {
        }

        public PhoneInfo(String phoneNr) {
            this.phoneNr = phoneNr;
        }

        public String getPhoneNr() {
            return phoneNr;
        }

        public void setPhoneNr(String phoneNr) {
            this.phoneNr = phoneNr;
        }
    }

    public static class EmailInfo extends ContactInfo{
        String emailAddress;

        public EmailInfo() {
        }

        public EmailInfo(String emailAddress) {
            this.emailAddress = emailAddress;
        }

        public String getEmailAddress() {
            return emailAddress;
        }

        public void setEmailAddress(String emailAddress) {
            this.emailAddress = emailAddress;
        }


    }

    ClassNode createMetaInfo() throws TokenStreamException, RecognitionException {
        String modelString = "metamodel.PolyTest$Person(\n" +
                "                           name,\n" +
                "                           contactInfo:switch(metamodel.PolyTest$ContactInfo)(\n" +
                "                                       metamodel.PolyTest$EmailInfo(emailAddress),\n" +
                "                                       metamodel.PolyTest$PhoneInfo(phoneNr)\n" +
                "                           ),\n" +
                "                           secondaryInfos:collection(\n" +
                "                                      switch(metamodel.PolyTest$ContactInfo)(\n" +
                "                                          metamodel.PolyTest$EmailInfo(emailAddress),\n" +
                "                                          metamodel.PolyTest$PhoneInfo(phoneNr)\n" +
                "                                       )\n" +
                "                           )\n" +
                "                    )";
        System.out.println(modelString);
        return TraversalUtils.parse(modelString);
    }

    public void testParsing() throws TokenStreamException, RecognitionException {
        createMetaInfo();
    }
    public void testClone() throws TokenStreamException, RecognitionException {
        Person felix=new Person("Felix");
        felix.setContactInfo(new PhoneInfo("5854"));
        ClassNode meta=createMetaInfo();
        Object clone= TraversalUtils.clone(meta,felix);
        assertTrue(TraversalUtils.equals(meta,felix,clone));


    }
    public void testPrinting() throws TokenStreamException, RecognitionException {
        Person felix = createTestPerson();

        ClassNode meta=createMetaInfo();
        StringWriter out=new StringWriter();
        TraversalUtils.print(meta,felix,out);
        System.out.println(out.getBuffer().toString());
    }

    public void testSerialization() throws TokenStreamException, RecognitionException {
        Person felix= createTestPerson();
        ClassNode meta= createMetaInfo();
        assertEquals("(\"Felix\",(metamodel.PolyTest$PhoneInfo,\"5854\"),[(metamodel.PolyTest$PhoneInfo,\"905488\"),(metamodel.PolyTest$EmailInfo,\"felix.leipold@gmx.de\")])", TraversalUtils.serialize(meta,felix));
    }

    public void testDeserialization() throws TokenStreamException, RecognitionException, IOException {
        ClassNode meta= createMetaInfo();
        long t1=System.currentTimeMillis();
        Object clone= TraversalUtils.deserialize(meta,"(\"Felix\",(metamodel.PolyTest$PhoneInfo,\"5854\"),[(metamodel.PolyTest$PhoneInfo,\"905488\"),(metamodel.PolyTest$EmailInfo,\"felix.leipold@gmx.de\")])");
        long t2=System.currentTimeMillis();
        System.out.println("time: "+(t2-t1));
        assertTrue(TraversalUtils.equals(meta,clone,createTestPerson()));
    }

    private Person createTestPerson() {
        Person felix=new Person("Felix");
        felix.setContactInfo(new PhoneInfo("5854"));
        felix.getSecondaryInfos().add(new PhoneInfo("905488"));
        felix.getSecondaryInfos().add(new EmailInfo("felix.leipold@gmx.de"));
        return felix;
    }

    public void testXMLSerialisation() throws TokenStreamException, RecognitionException {
        Person felix=new Person("Felix");
        ClassNode meta=createMetaInfo();
        felix.setContactInfo(new PhoneInfo("5854"));
        felix.getSecondaryInfos().add(new PhoneInfo("905488"));
        felix.getSecondaryInfos().add(new EmailInfo("felix.leipold@gmx.de"));
        ByteArrayOutputStream bout = new ByteArrayOutputStream();

        XMLSerializer s=new XMLSerializer(meta,bout);
        s.serialize(felix);
        System.out.println(new String(bout.toByteArray()));
        System.out.println(TraversalUtils.toString(meta,felix));
    }

}
